import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.io.IOException;
import java.util.Iterator;

public class JsonMergeWithJackson {
    public static void main(String[] args) {
        String jsonString1 = "{\"department\": {\"name\": \"IT\", \"employees\": [{\"id\": 1, \"name\": \"John\", \"skills\": [\"Java\", \"Python\"]}, {\"id\": 2, \"name\": \"Alice\", \"skills\": [\"JavaScript\", \"CSS\"]}]}}";
        String jsonString2 = "{\"department\": {\"name\": \"Engineering\", \"employees\": [{\"id\": 1, \"name\": \"Tom\", \"skills\": [\"C++\", \"Go\"]}, {\"id\": 3, \"name\": \"Bob\", \"skills\": [\"Ruby\", \"Rails\"]}]}}";

        try {
            System.out.println(jsonString1 );
            System.out.println(jsonString2 );
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode jsonNode1 = objectMapper.readTree(jsonString1);
            JsonNode jsonNode2 = objectMapper.readTree(jsonString2);

            System.out.println(System.currentTimeMillis());
            JsonNode mergedNode = mergeJsonNodes(jsonNode1, jsonNode2);
            System.out.println(System.currentTimeMillis());
            String mergedJson = objectMapper.writeValueAsString(mergedNode);
            System.out.println(mergedJson);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 整体流程：
     * 首先使用 ObjectMapper 的 readTree 方法将两个 JSON 字符串解析为 JsonNode 对象（jsonNode1 和 jsonNode2）。
     * 然后调用 mergeJsonNodes 方法进行合并操作，该方法根据节点类型（对象节点或数组节点等）来执行相应的合并逻辑，最后返回合并后的 JsonNode 对象。
     * 再通过 ObjectMapper 的 writeValueAsString 方法把合并后的 JsonNode 对象转换回 JSON 字符串并输出。
     * mergeJsonNodes 方法逻辑：
     * 先判断传入的两个节点是否为 ObjectNode 类型，如果是，则遍历更新节点（updateObjectNode）的字段名。
     * 对于每个字段，获取其对应的值节点（updateFieldValue），再看源节点（sourceObjectNode）是否存在同名字段，
     *    若存在，获取其对应的值节点（sourceFieldValue），接着按以下情况处理：
     *      如果两个值节点都是对象节点，递归调用 mergeJsonNodes 方法来合并它们内部的字段，并将合并后的子节点设置回源节点对应的字段位置。
     *      如果两个值节点都是数组节点，则调用 mergeArrayNodes 方法来合并数组元素，合并后数组保持在源节点对应的字段位置。
     *      如果是其他情况（非对象、非数组），直接用更新节点的值替换源节点对应字段的值。
     *    若源节点不存在该字段，则直接将该字段及其值添加到源节点中。
     * 最后返回合并后的源节点（sourceObjectNode）作为合并结果。
     * mergeArrayNodes 方法逻辑：
     * 遍历更新数组节点（updateArrayNode）中的每个元素（假设每个元素是对象且包含用于唯一标识的 id 字段，可根据实际情况调整此判断依据）。
     * 在源数组节点（sourceArrayNode）中查找是否有与之 id 相同的元素，如果找到，递归调用 mergeJsonNodes 方法合并这两个对象元素，并将合并后的元素替换源数组中对应的元素位置；如果没找到匹配的元素，则将更新数组中的该元素添加到源数组中。
     * @param source
     * @param update
     * @return
     */

    private static JsonNode mergeJsonNodes(JsonNode source, JsonNode update) {
        if (source instanceof ObjectNode && update instanceof ObjectNode) {
            ObjectNode sourceObjectNode = (ObjectNode) source;
            ObjectNode updateObjectNode = (ObjectNode) update;

            Iterator<String> fieldNames = updateObjectNode.fieldNames();
            while (fieldNames.hasNext()) {
                String fieldName = fieldNames.next();
                JsonNode updateFieldValue = updateObjectNode.get(fieldName);
                if (sourceObjectNode.has(fieldName)) {
                    JsonNode sourceFieldValue = sourceObjectNode.get(fieldName);
                    if (sourceFieldValue.isObject() && updateFieldValue.isObject()) {
                        // 递归合并对象节点
                        JsonNode mergedChildNode = mergeJsonNodes(sourceFieldValue, updateFieldValue);
                        ((ObjectNode) sourceObjectNode).set(fieldName, mergedChildNode);
                    } else if (sourceFieldValue.isArray() && updateFieldValue.isArray()) {
                        // 合并数组节点
                        ArrayNode sourceArrayNode = (ArrayNode) sourceFieldValue;
                        ArrayNode updateArrayNode = (ArrayNode) updateFieldValue;
                        mergeArrayNodes(sourceArrayNode, updateArrayNode);
                    } else {
                        // 替换值
                        sourceObjectNode.set(fieldName, updateFieldValue);
                    }
                } else {
                    // 新增字段
                    sourceObjectNode.set(fieldName, updateFieldValue);
                }
            }
            return sourceObjectNode;
        }
        return update;
    }

    private static void mergeArrayNodes(ArrayNode sourceArrayNode, ArrayNode updateArrayNode) {
        for (JsonNode updateNode : updateArrayNode) {
            boolean isMatched = false;
            for (int i = 0; i < sourceArrayNode.size(); i++) {
                JsonNode sourceNode = sourceArrayNode.get(i);
                if (sourceNode.isObject() && updateNode.isObject()) {
                    // 假设对象中有唯一标识字段 "id" 用于判断是否为同一元素，可按需调整
                    String updateId = updateNode.get("id").asText();
                    String sourceId = sourceNode.get("id").asText();
                    if (updateId.equals(sourceId)) {
                        // 递归合并匹配到的对象元素
                        JsonNode mergedChildNode = mergeJsonNodes(sourceNode, updateNode);
                        ((ArrayNode) sourceArrayNode).set(i, mergedChildNode);
                        isMatched = true;
                        break;
                    }
                }
            }
            if (!isMatched) {
                // 添加新元素到源数组
                sourceArrayNode.add(updateNode);
            }
        }
    }

}